package com.example.java_gobang.game;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.mapper.UserMapper;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

@Slf4j
//@Component  单例不行，每个房间都要一个房间对象。 手动注入
public class Room {
    private String roomId;

    private User user1;
    private User user2;

    private Integer whiteUser;

    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;

    // 0 —— 未落子、 1 —— 玩家1、 2 —— 玩家2
    private int[][] board = new int[MAX_ROW][MAX_COL];  //使用 int 默认才为 0; Integer 默认是 null;

    private ObjectMapper objectMapper = new ObjectMapper();

//    @Autowired  手动注入
    private OnlineUserManager onlineUserManager;

//    @Autowired   采用手动注入
    private RoomManager roomManager;

    private UserMapper userMapper;

    /*该方法用于 处理一次落子请求
    * 要做的事情：
    * 1. 记录落子位置
    * 2. 胜负判定
    * 3. 给前端返回响应*/
    public void putChess(String jsonStr) throws IOException {
        //1. 记录落子位置
        GameRequest gameRequest = objectMapper.readValue(jsonStr, GameRequest.class);
        GameResponse gameResponse = new GameResponse();
        Integer row = gameRequest.getRow();
        Integer col = gameRequest.getCol();
        Integer chess = gameRequest.getUserId() == user1.getUserId() ? 1 : 2;
        if (board[row][col] != 0) {
            log.info("[putChess]: row：{}， col：{} 已有棋子",row,col);
            return;
        }
        board[row][col] = chess;
        //2. 打印棋盘信息，方便后续验证胜负
        printBoard();
        //3. 胜负判定
        Integer winner = checkWin(row,col,chess);

        //4. 给房间中的用户返回响应。
        gameResponse.setMessage("putChess");
        gameResponse.setRow(row);
        gameResponse.setCol(col);
        gameResponse.setUserId(gameRequest.getUserId());
        gameResponse.setWinner(winner);


        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        //检查玩家是否下线
        if (session1 == null) {
            gameResponse.setWinner(user2.getUserId());
            log.info("user1: {},掉线",user1.getUserId());
        }
        if (session2 == null) {
            gameResponse.setWinner(user1.getUserId());
            log.info("user2: {},掉线",user2.getUserId());
        }

        String responseJSON = objectMapper.writeValueAsString(gameResponse);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(responseJSON));
        }
        if (session2 != null) {
            session2.sendMessage(new TextMessage(responseJSON));
        }

        if (gameResponse.getWinner() != 0) {
            log.info("[putChess],游戏结束 房间即将销毁 roomId: {}，获胜方：{}",roomId,gameResponse.getWinner());
            // 获胜者 总场数+1  胜场数+1 天梯分数+30
            // 失败者 总场数+1  胜场数不变 天梯分数-30
            int userWinId = gameResponse.getWinner();
            userMapper.userWin(userWinId);
            int userLoseId = (userWinId == user1.getUserId()) ? user2.getUserId() : user1.getUserId();
            userMapper.userLose(userLoseId);
            // 销毁房间
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
        }

    }

    private void printBoard() {
        // 打印棋盘信息
        System.out.println("当前棋盘信息：roomId：" + roomId);
        System.out.println("======================================================");
        for (int i = 0; i < MAX_ROW; i++) {
            for (int j = 0; j < MAX_COL; j++) {
                System.out.print(board[i][j] + "  ");
            }
            System.out.println();
        }
        System.out.println("======================================================");
    }

    private Integer checkWin(int row, int col, int chess) {
        //检查行
        for (int c = col - 4; c <= col; c++) {
            try {
                if (board[row][c] == chess
                && board[row][c+1] == chess
                && board[row][c+2] == chess
                && board[row][c+3] == chess
                && board[row][c+4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        //检测列
        for (int r = row-4; r <= row; r++) {
            try {
                if (board[r][col] == chess
                && board[r+1][col] == chess
                && board[r+2][col] == chess
                && board[r+3][col] == chess
                && board[r+4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        //检测主对角线
        for (int r = row-4, c = col-4; (r <= row) && (c <= col); r++,c++) {
            try {
                if (board[r][c] == chess
                && board[r+1][c+1] == chess
                && board[r+2][c+2] == chess
                && board[r+3][c+3] == chess
                && board[r+4][c+4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        //检测副对角线
        for (int r = row-4, c = col+4; (r <= row) && (c >= col); r++,c--) {
            try {
                if (board[r][c] == chess
                && board[r+1][c-1] == chess
                && board[r+2][c-2] == chess
                && board[r+3][c-3] == chess
                && board[r+4][c-4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        //胜负未分
        return 0;
    }

    public Integer getWhiteUser() {
        return whiteUser;
    }

    public void setWhiteUser(Integer whiteUser) {
        this.whiteUser = whiteUser;
    }

    public Room() {
        this.roomId = UUID.randomUUID().toString();
        onlineUserManager = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);
    }

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public User getUser1() {
        return user1;
    }

    public void setUser1(User user1) {
        this.user1 = user1;
    }

    public User getUser2() {
        return user2;
    }

    public void setUser2(User user2) {
        this.user2 = user2;
    }

}
